package com.peak.distribution.tools;

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class QrCodes {
	
	/** 编码格式 */
	private String charset = "utf-8";

	/** 二维码尺寸，正方形，所以设置一个就好 */
	private int size = 300;
	
	/** 生成的二维码图片 */
	private BufferedImage image;
	
	/** 中间的LOGO */
	private Logo logo;
	
	/** 二维码的内容 */
	private String content = "";
	
	public BufferedImage build() {
		Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
		hints.put(EncodeHintType.CHARACTER_SET, this.charset);
		hints.put(EncodeHintType.MARGIN, 0);
		BitMatrix bitMatrix;
		try {
			bitMatrix = new MultiFormatWriter().encode(this.content, BarcodeFormat.QR_CODE, this.size, this.size, hints);
			int width = bitMatrix.getWidth();
			int height = bitMatrix.getHeight();
			this.image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			for (int x = 0; x < width; x++) {
				for (int y = 0; y < height; y++) {
					this.image.setRGB(x, y, bitMatrix.get(x, y) ? 0x000000 : 0xFFFFFFFF);
				}
			}
			if (this.logo != null) {
				insertLogo(this.logo);
			}
		} catch (WriterException e) {
			throw new RuntimeException("二维码图片生成失败", e);
		} catch (IOException e) {
			throw new RuntimeException("二维码LOGO图片读取失败", e);
		}
		return this.image;
	}
	
	private void insertLogo(Logo logo) throws IOException {
		BufferedImage src = null;
		String scheme = logo.imageURI.getScheme();
		if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) {
			InputStream istream = null;
	        try {
	            istream = logo.imageURI.toURL().openStream();
	        } catch (IOException e) {
	        	log.error("图片地址无法访问。", e);
	        	return;
	        }
			src = ImageIO.read(istream);
		} else {
			File file = new File(logo.imageURI);
			if (!file.exists()) {
				log.error("文件{}不存在！", logo.imageURI.getPath());
				return;
			}
			src = ImageIO.read(file);
		}

		int width = src.getWidth(null);
		int height = src.getHeight(null);
		if (width > logo.width) {
			width = logo.width;
		}
		if (height > logo.height) {
			height = logo.height;
		}
		Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
		BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics g = tag.getGraphics();
		g.drawImage(image, 0, 0, null); // 绘制缩小后的图
		g.dispose();
		// 插入LOGO
		Graphics2D graph = this.image.createGraphics();
		int x = (this.size - width) / 2;
		int y = (this.size - height) / 2;
		graph.drawImage(image, x, y, width, height, null);
		Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
		graph.setStroke(new BasicStroke(3f));
		graph.draw(shape);
		graph.dispose();
	}
	
	public QrCodes content(String content) {
		this.content = content;
		return this;
	}
	
	public QrCodes size(int size) {
		this.size = size;
		return this;
	}
	
	public Logo logo() {
		this.logo = new Logo(this);
		return this.logo;
	}
	
	public static QrCodes create() {
		return new QrCodes();
	}
	
	public class Logo {
		/** 中间图片宽度 */
		int width = 60;
		
		/** 中间图片高度 */
		int height = 60;
		
		/** LOGO图片 */
		URI imageURI;
		
		/** 父类 */
		QrCodes qrCodes;
		
		public Logo(QrCodes qrCodes) {
			super();
			this.qrCodes = qrCodes;
		}

		public Logo width(int width) {
			this.width = width;
			return this;
		}
		
		public Logo height(int height) {
			this.height = height;
			return this;
		}
		
		public Logo imageURI(URI imageURI) {
			this.imageURI = imageURI;
			return this;
		}
		
		public QrCodes end() {
			return this.qrCodes;
		}
	}
}
